#ifndef STX_PLATFORM_POSIX_THREAD_BARRIER_HPP
#define STX_PLATFORM_POSIX_THREAD_BARRIER_HPP

#include <stx/platform/posix/thread/common.hpp>
#include <stx/platform/posix/thread/barrier_attributes.hpp>

namespace stx {

namespace posix {

class barrier: noncopyable
{
public:
    
    typedef barrier this_type;
    
    barrier(unsigned count)
    {
        int ret = pthread_barrier_init(&handle_, NULL, count);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_barrier_init");
        }
    }
    
    barrier(const barrier_attributes& attr, unsigned count)
    {
        int ret = pthread_barrier_init(&handle_, attr.handle(), count);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutex_init");
        }
    }
    
    ~barrier()
    {
        int ret = pthread_barrier_destroy(&handle_);
        if (ret) {
            STX_DESTRUCTOR_SYSTEM_ERROR_VAL(ret, "pthread_barrier_destroy");
        }
    }
    
    void wait()
    {
        int ret = pthread_barrier_wait(&handle_);
        if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_barrier_wait");
        }
    }
    
    typedef pthread_barrier_t handle_type;
    
    handle_type* handle()
    {
        return &handle_;
    }
    
    const handle_type* handle() const
    {
        return &handle_;
    }
    
private:
    
    handle_type handle_;
};

} // namespace posix

} // namespace stx

#endif // STX_PLATFORM_POSIX_THREAD_BARRIER_HPP
